package Controller;

import Model.ImageModel;
import View.DustDialog.DustDialog;
import View.GridDialog.GridDialog;
import View.LogDialog.LogDialog;
import View.MainFrame;
import View.MeanShiftDialog.MeanShiftDialog;
import View.MedianFilterDialog.MedianFilterDialog;
import View.MotionBlurDialog.MotionBlurDialog;
import View.SaltPepperDialog.SaltPepperDialog;
import View.SpinBlurDialog.SpinBlurDialog;
import View.UserFilterDialog.UserFilterDialog;
import View.WhiteNoiseDialog.WhiteNoiseDialog;
import View.ZoomBlurDialog.ZoomBlurDialog;
import View.kMeansDialog.KMeansDialog;
import View.setFolderDialog.SetFolderDialog;
import com.sun.jmx.snmp.tasks.Task;
import sun.misc.MessageUtils;
import sun.misc.resources.Messages;

import javax.swing.*;
import javax.swing.plaf.ProgressBarUI;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

public class Controller implements ActionListener {
    private MainFrame parentFrame;
    private JFileChooser openFileChooser;
    private JFileChooser saveFileChooser;
    private UserFilterDialog userFilterDialog;
    private WhiteNoiseDialog whiteNoiseDialog;
    private DustDialog dustDialog;
    private GridDialog gridDialog;
    private File selectedFile;
    private ImageModel imageModel;
    private UserFilterDialogController dialogController;
    private MedianFilterDialog medianFilterDialog;
    private MotionBlurDialog motionBlurDialog;
    private ZoomBlurDialog zoomBlurDialog;
    private SpinBlurDialog spinBlurDialog;
    private KMeansDialog kMeansDialog;
    private LogDialog logDialog;
    private MeanShiftDialog meanShiftDialog;
    private SaltPepperDialog saltPepperDialog;


    public Controller(MainFrame frame, ImageModel model) {
        parentFrame = frame;
        imageModel = model;
        imageModel.setListener(parentFrame);
        userFilterDialog = new UserFilterDialog(parentFrame);
        whiteNoiseDialog = new WhiteNoiseDialog(parentFrame);
        saltPepperDialog = new SaltPepperDialog(parentFrame);
        dustDialog = new DustDialog(parentFrame);
        gridDialog = new GridDialog(parentFrame);
        dialogController = new UserFilterDialogController(imageModel);
        userFilterDialog.setListener(dialogController);
        medianFilterDialog = new MedianFilterDialog(parentFrame);
        motionBlurDialog = new MotionBlurDialog(parentFrame);
        zoomBlurDialog = new ZoomBlurDialog(parentFrame);
        spinBlurDialog = new SpinBlurDialog(parentFrame);
        logDialog = new LogDialog(parentFrame);
        kMeansDialog = new KMeansDialog(parentFrame);
        meanShiftDialog = new MeanShiftDialog(parentFrame);


        //goldenImageFolderDialog = new SetFolderDialog(parentFrame, parentFrame.getImageModel().getGoldenImagePath(), "Golden image path");
        //differenceFolderDialog = new SetFolderDialog(parentFrame, parentFrame.getImageModel().getDiffPath(), "Difference path");
        //userFilterDialog.add
    }

    private void saveSelectedFile(File selectedFile) {
        if (selectedFile != null) {
            String extension = Utils.getExtension(selectedFile);
            String path = selectedFile.getAbsolutePath();
            if (extension == null) {
                extension = ((SaveImageFilter) (saveFileChooser.getFileFilter())).getExtension();
                path += "." + extension;
            }
            imageModel.save(path, extension);
        }
    }

    private void executeFilter(final Runnable r) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                parentFrame.disableButtons();
                parentFrame.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
                try {
                    r.run();
                } catch (Throwable e) {
                    e.printStackTrace();
                    JOptionPane.showMessageDialog(parentFrame, "Unexpected error. Filter wasn't applied", "Error", JOptionPane.ERROR_MESSAGE);
                } finally {
                  parentFrame.setDefaults();
                  parentFrame.setCursor(Cursor.getDefaultCursor());
                }

            }
        });


    }

    public void actionPerformed(ActionEvent ae) {
        if (ae.getActionCommand().equals(MainFrame.OPEN_COMMAND)) {
            if (openFileChooser == null) {
                openFileChooser = new JFileChooser();
                openFileChooser.setAcceptAllFileFilterUsed(false);
                openFileChooser.setFileFilter(new OpenImageFilter());
            }
            if (imageModel.getFile() == null) {
                openFileChooser.setCurrentDirectory(new File("."));
            } else {
                openFileChooser.setCurrentDirectory(imageModel.getFile());
            }
            int returnVal = openFileChooser.showOpenDialog(parentFrame);
            if (returnVal == JFileChooser.APPROVE_OPTION) {
                imageModel.open(openFileChooser.getSelectedFile());
            }
            openFileChooser.setSelectedFile(null);
        }
        if (ae.getActionCommand().equals(MainFrame.SAVE_COMMAND)) {
            if (imageModel.getFile() != null)
                saveSelectedFile(imageModel.getFile());
        }
        if (ae.getActionCommand().equals(MainFrame.SAVE_AS_COMMAND)) {
            if (saveFileChooser == null) {
                saveFileChooser = new JFileChooser();
                saveFileChooser.setAcceptAllFileFilterUsed(false);
                saveFileChooser.addChoosableFileFilter(new SaveImageFilter("BMP file", "bmp"));
                saveFileChooser.addChoosableFileFilter(new SaveImageFilter("JPEG file", "jpg"));
                saveFileChooser.addChoosableFileFilter(new SaveImageFilter("PNG file", "png"));
            }
            if (imageModel.getFile() != null) {
                saveFileChooser.setCurrentDirectory(imageModel.getFile());
            }
            int returnVal = saveFileChooser.showSaveDialog(parentFrame);
            if (returnVal == JFileChooser.APPROVE_OPTION) {
                saveSelectedFile(saveFileChooser.getSelectedFile());
            }
            saveFileChooser.setSelectedFile(null);
        }
        if (ae.getActionCommand().equals(MainFrame.EROSION_COMMAND)) {
            executeFilter(new Runnable() {
                public void run() {
                    imageModel.erosion(3);
                }
            });

        }
        if (ae.getActionCommand().equals(MainFrame.DILATATION_COMMAND)) {
            executeFilter(new Runnable() {
                public void run() {
                  imageModel.dilatation(3);
                }
            });

        }
        if (ae.getActionCommand().equals(MainFrame.INVERSION_COMMAND)) {
            executeFilter(new Runnable() {
                public void run() {
                    imageModel.inversion();
                }
            });

        }
        if (ae.getActionCommand().equals(MainFrame.WB_COMMAND)) {
            executeFilter(new Runnable() {
                public void run() {
                    imageModel.bw();
                }
            });

        }
        if (ae.getActionCommand().equals(MainFrame.LINFILTER_COMMAND)) {
            executeFilter(new Runnable() {
                public void run() {
                    userFilterDialog.setVisible(true);
                }
            });

        }
        if (ae.getActionCommand().equals(MainFrame.WHITENOISE_COMMAND)) {
            boolean res = whiteNoiseDialog.runDialog();
            if (res) {
                final float p = whiteNoiseDialog.getProb();
                final int d = whiteNoiseDialog.getDiap();
                executeFilter(new Runnable() {
                    public void run() {
                        imageModel.WhiteNoise(p, d);
                    }
                });

            }
        }
        if (ae.getActionCommand().equals(MainFrame.SALT_PEPPER)) {
            boolean res = saltPepperDialog.runDialog();
            if (res) {
                final double p = saltPepperDialog.getProb();
                executeFilter(new Runnable() {
                    public void run() {
                        imageModel.saltPepper(p);
                    }
                });

            }
        }
        if (ae.getActionCommand().equals(MainFrame.DUST_COMMAND)) {
            boolean res = dustDialog.runDialog();
            if (res) {
                final float p = dustDialog.getProb();
                final int min = dustDialog.getMin();
                executeFilter(new Runnable() {
                    public void run() {
                        imageModel.Dust(p, min);
                    }
                });

            }
        }
        if (ae.getActionCommand().equals(MainFrame.MEDIAN_COMMAND)) {
            boolean res = medianFilterDialog.runDialog();
            if (res) {
                final int r = medianFilterDialog.getR();
                executeFilter(new Runnable() {
                    public void run() {
                        imageModel.medianFilter(r);
                    }
                });

            }

        }
        if (ae.getActionCommand().equals(MainFrame.MOTION_BLUR)) {
            boolean res = motionBlurDialog.runDialog();
            if (res) {
                executeFilter(new Runnable() {
                    public void run() {
                        imageModel.motionBlur((float) Math.PI * motionBlurDialog.getAngle() / 180.0f,
                                motionBlurDialog.getDistance(), motionBlurDialog.getIterations());
                    }
                });

            }
        }
        if (ae.getActionCommand().equals(MainFrame.ZOOM_BLUR)) {
            boolean res = zoomBlurDialog.runDialog();
            if (res) {
                executeFilter(new Runnable() {
                    public void run() {
                        imageModel.zoomBlur(zoomBlurDialog.getScale(), zoomBlurDialog.getIterations());
                    }
                });

            }
        }
        if (ae.getActionCommand().equals(MainFrame.SPIN_BLUR)) {
            boolean res = spinBlurDialog.runDialog();
            if (res) {
                executeFilter(new Runnable() {
                    public void run() {
                        imageModel.spinBlur((float) Math.PI * spinBlurDialog.getAngle() / 180.0f, spinBlurDialog.getIterations());
                    }
                });

            }
        }
        if (ae.getActionCommand().equals(MainFrame.LOG_COMMAND)) {
            boolean res = logDialog.runDialog();
            if (res) {
                executeFilter(new Runnable() {
                    public void run() {
                        imageModel.LoG(logDialog.getR(), logDialog.getSigma());
                    }
                });

            }
        }
        if (ae.getActionCommand().equals(MainFrame.K_MEANS)) {
            boolean res = kMeansDialog.runDialog();
            if (res) {
                executeFilter(new Runnable() {
                    public void run() {
                        imageModel.k_means(kMeansDialog.getK(), kMeansDialog.getIterations(), kMeansDialog.getLambda());
                    }
                });

            }
        }
        if (ae.getActionCommand().equals(MainFrame.MEANSHIFT)) {
            boolean res = meanShiftDialog.runDialog();
            if (res) {
                executeFilter(new Runnable() {
                    public void run() {
                        imageModel.meanShift(meanShiftDialog.getRd(), meanShiftDialog.getRc(),
                                meanShiftDialog.getIterations(), meanShiftDialog.getMaxLevel());
                    }
                });

                //imageModel.meanShift(10, 35, 1000, 3);
            }
        }
        if (ae.getActionCommand().equals(MainFrame.UNDO_COMMAND)) {
            imageModel.undo();
        }
        if (ae.getActionCommand().equals(MainFrame.REDO_COMMAND)) {
            imageModel.redo();
        }
        if (ae.getActionCommand().equals(MainFrame.GRID_COMMAND)) {
            if (parentFrame.getMyImagePanel().isGridPainted()) {
                parentFrame.getMyImagePanel().setGridPainted(false);
            } else {
                boolean res = gridDialog.runDialog();
                if (res) {
                    int w = gridDialog.getW();
                    int h = gridDialog.getH();
                    Color c = gridDialog.getC();
                    parentFrame.getMyImagePanel().setGrid(w, h, c);
                    parentFrame.getMyImagePanel().setGridPainted(true);
                }
            }
        }
        if (ae.getActionCommand().equals(MainFrame.GOLDENIMAGE_COMMAND)) {
            imageModel.setGoldenImagePath(SetFolderDialog.runDialog(parentFrame, imageModel.getGoldenImagePath()));
        }
        if (ae.getActionCommand().equals(MainFrame.DIFF_COMMAND)) {
            imageModel.setDiffPath(SetFolderDialog.runDialog(parentFrame, imageModel.getDiffPath()));
        }
        if (ae.getActionCommand().equals(MainFrame.COMPARE_COMMAND)) {
            final int[] res = new int[1];
            executeFilter(new Runnable() {
                public void run() {
                    res[0] = imageModel.compare();
                }
            });

            if (res[0] == -1) {
                JOptionPane.showMessageDialog(parentFrame, "No file with such name in golden image path", "Error!", JOptionPane.ERROR_MESSAGE);
            } else if (res[0] == -2) {
                JOptionPane.showMessageDialog(parentFrame, "Bad size of the golden image", "Error!", JOptionPane.ERROR_MESSAGE);
            } else {
                JOptionPane.showMessageDialog(parentFrame, "Result = " + res[0], "Result", JOptionPane.INFORMATION_MESSAGE);
            }

        }
        if (ae.getActionCommand().equals(MainFrame.EXIT_COMMAND)) {
            parentFrame.closeWindow();
        }
    }

    public void disposeDialogs() {
        dustDialog.dispose();
        whiteNoiseDialog.dispose();
        gridDialog.dispose();
        medianFilterDialog.dispose();
        saltPepperDialog.dispose();
        motionBlurDialog.dispose();
        zoomBlurDialog.dispose();
        spinBlurDialog.dispose();
        kMeansDialog.dispose();
        logDialog.dispose();
        meanShiftDialog.dispose();
    }
}
